package com.xingchi.tornado.dict.service;

import com.beust.jcommander.internal.Lists;
import com.google.common.collect.Maps;
import com.xingchi.tornado.core.lock.RedisLock;
import com.xingchi.tornado.dict.constants.DictConstants;
import com.xingchi.tornado.dict.enums.DictStorageTypeEnum;
import com.xingchi.tornado.dict.model.DictMetadata;
import com.xingchi.tornado.dict.model.dto.DictDTO;
import com.xingchi.tornado.dict.model.dto.DictQueryDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 数据库存储
 *
 * @author xingchi
 * @date 2024/5/19 20:41
 */
@Slf4j
public class JdbcDictStorageService implements DictStorageService {

    private final DictService dictService;

    public JdbcDictStorageService(DictService dictService) {
        this.dictService = dictService;
    }

    /**
     * 存储字典数据
     *
     * @param dictMetadataList 字典数据集合
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void storage(List<DictMetadata> dictMetadataList) {

        if (CollectionUtils.isEmpty(dictMetadataList)) {
            return;
        }

        boolean isLock = RedisLock.tryLock(DictConstants.JDBC_STORAGE_LOCK_KEY);
        try {
            if (isLock) {
                Map<String, List<DictDTO>> groupDictMappings = this.toDictDTO(dictMetadataList);
                for (Map.Entry<String, List<DictDTO>> entry : groupDictMappings.entrySet()) {
                    String group = entry.getKey();
                    List<DictDTO> dictList = entry.getValue();
                    List<DictDTO> existsDictData = dictService.selectByQuery(DictQueryDTO.builder().group(group).build());
                    if (CollectionUtils.isEmpty(existsDictData)) {
                        // 直接进行批量插入
                        dictService.saveBatch(dictList);
                    } else {
                        // 遍历旧数据，如果存在则更新，否则新增
                        Map<Integer, DictDTO> codeGroupMappings = existsDictData.stream().collect(Collectors.toMap(DictDTO::getCode, Function.identity(), (old, newValue) -> old));
                        for (DictDTO dictDTO : dictList) {
                            if (codeGroupMappings.containsKey(dictDTO.getCode())) {
                                // 存在则更新
                                dictDTO.setId(codeGroupMappings.get(dictDTO.getCode()).getId());
                                dictService.updateById(dictDTO);
                            } else {
                                // 否则则进行插入
                                dictService.insert(dictDTO);
                            }
                        }
                    }
                }
            }
        } finally {
            RedisLock.unlock(DictConstants.JDBC_STORAGE_LOCK_KEY);
        }
    }

    public Map<String, List<DictDTO>> toDictDTO(List<DictMetadata> dictMetadataList) {

        Map<String, List<DictDTO>> result = new HashMap<>();
        for (DictMetadata dictMetadata : dictMetadataList) {
            List<DictDTO> items = Optional.ofNullable(dictMetadata.getItems()).orElse(new ArrayList<>())
                    .stream()
                    .map(item -> {
                        DictDTO dictDTO = new DictDTO();
                        dictDTO.setGroup(dictMetadata.getGroup());
                        dictDTO.setName(item.getName());
                        dictDTO.setCode(item.getCode());
                        dictDTO.setDesc(item.getDesc());
                        dictDTO.setSort(item.getOrder());
                        dictDTO.setVisible(item.getVisible() ? 1 : 0);
                        return dictDTO;
                    }).collect(Collectors.toList());
            result.put(dictMetadata.getGroup(), items);
        }

        return result;
    }

    /**
     * 获取所有字典项
     *
     * @return 所有字典项
     */
    @Override
    public Map<String, List<DictMetadata.Item>> getAllDictItems() {

        List<DictDTO> result = dictService.selectByQuery(DictQueryDTO.builder().build());
        if (CollectionUtils.isEmpty(result)) {
            return Maps.newHashMap();
        }

        return result.stream().collect(Collectors.groupingBy(DictDTO::getGroup, Collectors.mapping(this::toItem, Collectors.toList())));
    }

    public DictMetadata.Item toItem(DictDTO dictDTO) {
        DictMetadata.Item item = new DictMetadata.Item();
        item.setName(dictDTO.getName());
        item.setCode(dictDTO.getCode());
        item.setDesc(dictDTO.getDesc());
        item.setOrder(dictDTO.getSort());
        item.setVisible(dictDTO.getVisible() == 1);
        return item;
    }

    /**
     * 根据字典分组获取字典数据
     *
     * @param group 分组项
     * @return 字典数据
     */
    @Override
    public List<DictMetadata.Item> getDictItems(String group) {

        List<DictDTO> result = dictService.selectByQuery(DictQueryDTO.builder().group(group).build());
        if (CollectionUtils.isEmpty(result)) {
            return Lists.newArrayList();
        }

        return result.stream().map(this::toItem).collect(Collectors.toList());
    }

    /**
     * 存储类型
     *
     * @param storageType 存储类型
     * @return 是否支持
     */
    @Override
    public boolean supports(Integer storageType) {
        return DictStorageTypeEnum.JDBC.isType(storageType);
    }
}
